package com.xiaoba.search.service.impl;

import com.alibaba.fastjson2.JSON;
import com.xiaoba.common.core.domain.Result;
import com.xiaoba.common.core.utils.StringUtils;
import com.xiaoba.search.domain.SearchParam;
import com.xiaoba.search.domain.SearchResult;
import com.xiaoba.search.domain.SkuEsModel;
import com.xiaoba.search.feign.EsFeignService;
import com.xiaoba.product.domain.SkuInfo;
import com.xiaoba.search.service.SearchService;
import lombok.extern.log4j.Log4j2;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @Author: Gd
 * @package: com.xiaoba.search.service.impl
 * @Project: XiaoBa
 * @Name: SearchServiceImpl
 * @Date: 2024/5/29 15:24
 */
@Service
@Log4j2
public class SearchServiceImpl implements SearchService {

    @Autowired
    private EsFeignService esFeignService;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private static final String INDEX_NAME = "product";


    @Override
    public void delsAll() {
        try {
            DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(INDEX_NAME);
            deleteByQueryRequest.setQuery(QueryBuilders.matchAllQuery());
            restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 同步
     *
     * @param id
     * @return
     */
    @Override
    public Result sendputaway(Integer id) {

        Result<List<SkuInfo>> listResult = esFeignService.findskuAll(id);
        List<SkuInfo> skuInfos = listResult.getData();

        if (null == skuInfos) {
            return Result.error("数据发生异常，请联系管理员");
        }

        BulkRequest bulkRequest = new BulkRequest();
        for (SkuInfo skuInfo : skuInfos) {
            skuInfo.setHasstock(true);
            skuInfo.setHotscore(100L);

            if (skuInfos.size() > 0) {
                bulkRequest.add(new IndexRequest(INDEX_NAME).id(skuInfo.getSkuId().toString())
                        .source(JSON.toJSONString(skuInfo), XContentType.JSON));
            }

        }
        try {
            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Result.success();
    }

    /**
     * es查询
     *
     * @param param
     * @return
     */
    @Override
    public SearchResult seach(SearchParam param) {

        // 造数据
        /*SearchParam param = new SearchParam();*/

//        SearchSourceBuilder searchSourceBuilder = buildSourceBuilder(param);

//        SearchRequest searchRequest = new SearchRequest();
//        searchRequest.indices("product");
//        searchRequest.source(searchSourceBuilder);

        SearchRequest searchRequest = buildSourceBuilder(param);

        try {

            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            // searchResponse查出来的结果赋值给SkuEsModel


            //解析结果集
            SearchResult result = analyzerResponse(searchResponse, param);

            return result;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 解析结果集
     *
     * @param searchResponse
     * @return
     */
    private SearchResult analyzerResponse(SearchResponse searchResponse, SearchParam param) {

        // 创建查询返回值对象
        SearchResult result = new SearchResult();
        // 拿到响应数据
        SearchHits hits = searchResponse.getHits();

        // 3.1 products
        List<SkuEsModel> skuEsModels = new ArrayList<>();

        SearchHit[] hits1 = hits.getHits();
        skuEsModels = Arrays.stream(hits1).map(hit -> {

            SkuEsModel skuEsModel = JSON.parseObject(hit.getSourceAsString(), SkuEsModel.class);
            // 处理高亮
            if(StringUtils.isNotBlank(param.getKeyword())){
                HighlightField skuTitle = hit.getHighlightFields().get("skuTitle");
                skuEsModel.setSkuTitle(skuTitle.getFragments()[0].toString());
            }

            return skuEsModel;
        }).collect(Collectors.toList());

        // 商品信息
        result.setProducts(skuEsModels);


        // 3.2  pageNum total totalPages
        // 当前页
        result.setPageNum(param.getPageNum());
        // 每页条数
        result.setPageSize(param.getPageSize());
        // 总条数
        long recordsCount = hits.getTotalHits().value;
        result.setTotalPages(Integer.valueOf(String.valueOf((recordsCount % 20 == 0) ? (recordsCount / 20) : (recordsCount / 20 + 1))));
        result.setTotal(recordsCount);

        Aggregations aggregations = searchResponse.getAggregations();
        // 3.3 brands
        ParsedLongTerms brandIdAgg = aggregations.get("brandIdAgg");
        if (brandIdAgg != null && brandIdAgg.getBuckets().size() > 0) {
            // 聚合结果的桶列表不为空且大小大于零的情况下执行操作
            List<? extends Terms.Bucket> buckets = brandIdAgg.getBuckets();

            List<SearchResult.BrandVo> brandList = new ArrayList<>();

            for (Terms.Bucket bucket : buckets) {

                SearchResult.BrandVo brandVo = new SearchResult.BrandVo();

                String brandId = bucket.getKeyAsString();

//                ParsedStringTerms brandImgAgg = bucket.getAggregations().get("brandImgAgg");
//                String brandImg = brandImgAgg.getBuckets().get(0).getKeyAsString();

                ParsedStringTerms brandNameAgg = bucket.getAggregations().get("brandNameAgg");
                String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();

                brandVo.setBrandId(Long.valueOf(brandId));
                brandVo.setBrandName(brandName);
//                brandVo.setBrandImg(brandImg);

                brandList.add(brandVo);
                // 品牌信息
                result.setBrands(brandList);

            }

        }

        // 3.4 catalogs
        ParsedLongTerms catalogIdAgg = aggregations.get("catalogIdAgg");
        if (catalogIdAgg != null && catalogIdAgg.getBuckets().size() > 0) {
            // 聚合结果的桶列表不为空且大小大于零的情况下执行操作

            List<SearchResult.CatalogVo> catalogVoList = new ArrayList<>();

            for (Terms.Bucket bucket : catalogIdAgg.getBuckets()) {

                SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();

                String catalogId = bucket.getKeyAsString();

                ParsedStringTerms aggregation = bucket.getAggregations().get("catalogNameAgg");
                String catalogName = aggregation.getBuckets().get(0).getKeyAsString();

                catalogVo.setCatalogId(Long.valueOf(catalogId));
                catalogVo.setCatalogName(catalogName);

                catalogVoList.add(catalogVo);

            }
            // 商品规格信息  三级联动
            result.setCatalogs(catalogVoList);

        }

        // 3.5  attrs
        ParsedNested attrAgg = aggregations.get("attrAgg");
        ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attrIdAgg");

        ArrayList<SearchResult.AttrVo> attrList = new ArrayList<>();

        for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {

            SearchResult.AttrVo attrVo = new SearchResult.AttrVo();

            String attrId = bucket.getKeyAsString();

            ParsedStringTerms aggregation = bucket.getAggregations().get("attrNameAgg");
            String attrNameAgg = aggregation.getBuckets().get(0).getKeyAsString();

            ParsedStringTerms attrValueSubAgg = bucket.getAggregations().get("attrValueAgg");

            ArrayList<String> attrValueList = new ArrayList<>();

            for (Terms.Bucket attrValueSubAggBucket : attrValueSubAgg.getBuckets()) {
                String attrValueAgg = attrValueSubAggBucket.getKeyAsString();
                attrValueList.add(attrValueAgg);
            }

            attrVo.setAttrId(Long.valueOf(attrId));
            attrVo.setAttrName(attrNameAgg);
            attrVo.setAttrValue(attrValueList);

            attrList.add(attrVo);

        }
        // 商品属性信息
        result.setAttrs(attrList);

        return result;
    }

    /**
     * 查询数据
     *
     * @param param
     * @return
     */
    private SearchRequest buildSourceBuilder(SearchParam param) {

        // 创建搜索强求的主体部分
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 创建布尔查询的构建器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // 1、query  添加关键词查询的条件
        // 1.1 must  ==> keyword
        if (null != param.getKeyword() && StringUtils.isNotEmpty(param.getKeyword())) {
            boolQueryBuilder.must(
                    QueryBuilders.matchQuery("skuTitle", param.getKeyword())
            );
        }

        // 1.2 filter -->(不计算权重，性能好一点)
        // 1.2.1 brandId  多选
        if (null != param.getBrandId() && !param.getBrandId().isEmpty()) {
            System.out.println(param.getBrandId());
            boolQueryBuilder.filter(
                    QueryBuilders.termsQuery("brandId", param.getBrandId())
            );
        }
        // 1.2.2 catalogId  单选  比如 225
        if (null != param.getCatalog3Id()) {
            boolQueryBuilder.filter(
                    QueryBuilders.termQuery("catalogId", param.getCatalog3Id())
            );
        }

        // 1.2.3 range 添加价格范围过滤条件
        // 10-10000 split _tart _ends
        if (null != param.getSkuPrice() && StringUtils.isNotEmpty(param.getSkuPrice())) {
            RangeQueryBuilder skePrice = QueryBuilders.rangeQuery("skuPrice");
            String skuPrice = param.getSkuPrice();
            String[] split = skuPrice.split("_");
            if (split.length == 2) {
                skePrice.gte(split[0]);
                skePrice.lte(split[1]);
                boolQueryBuilder.filter(skePrice);
            } else if (split.length == 1 && param.getSkuPrice().startsWith("_")) {
                skePrice.lte(split[0]);
                boolQueryBuilder.filter(skePrice);
            } else if (split.length == 1 && param.getSkuPrice().endsWith("_")) {
                skePrice.gte(split[0]);
                boolQueryBuilder.filter(skePrice);
            }
        }

        // 1.2.4 hasstock
        if (boolQueryBuilder != null) {
            boolQueryBuilder.filter(
                    QueryBuilders.termsQuery("hasstock", true)
            );
        }

        // 1.2.5 attr
//        if (param.getAttrs() != null && param.getAttrs().size() > 0) {
//            for (String attrStr : param.getAttrs()) {
//
//                String[] s = attrStr.split("_");
//                String attrId = s[0];
//
//                String[] sttrValues = s[1].split("_");
//
//                BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//                boolQuery.must(QueryBuilders.termQuery("attrs.attrId", attrId));
//                boolQuery.must(QueryBuilders.termsQuery("attrs.attrValue", sttrValues));
//
//                NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", boolQuery, ScoreMode.None);
//                boolQueryBuilder.filter(attrs);
//            }
//        }
        sourceBuilder.query(boolQueryBuilder);

        // 2、sort   saleCount
//        if (null != param.getSkuPrice() && StringUtils.isNotEmpty(param.getSkuPrice())) {
//            RangeQueryBuilder saleCount = QueryBuilders.rangeQuery("skuPrice");
//            String saleCount1 = param.getSkuPrice();
//            String[] split = saleCount1.split("_");
//            if (split.length == 2) {
//                saleCount.gte(split[0]);
//                saleCount.lte(split[1]);
//                boolQueryBuilder.filter(saleCount);
//                sourceBuilder.sort(split[0], "asc".equalsIgnoreCase(split[1]) ? SortOrder.ASC : SortOrder.DESC);
//            }
//        }

        if (StringUtils.isNotEmpty(param.getSort())) {
            String[] strings = param.getSort().split("_");
                sourceBuilder.sort(strings[0], "asc".equalsIgnoreCase(strings[1]) ? SortOrder.ASC : SortOrder.DESC);
        }

//        sourceBuilder.sort("skuPrice", SortOrder.DESC);

        // 3、分页
        sourceBuilder.from((param.getPageNum() - 1) * param.getPageSize());
        sourceBuilder.size(param.getPageSize());

        // 4、 高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("skuTitle")
                .preTags("<span style=\"color:red;font-size:20px\">")
                .postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);
        // 5、 aggs
        // 5.1、brandIdAgg
        TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandIdAgg").field("brandId");
        // 添加品牌名称聚合
        if(null != brandIdAgg){
            TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandNameAgg").field("brandName");
            if(null != brandNameAgg){
                brandIdAgg.subAggregation(brandNameAgg);
            }
        }

        TermsAggregationBuilder catalogIdAgg = AggregationBuilders.terms("catalogIdAgg").field("catalogId");
        // 添加类别名称聚合
        if(null != catalogIdAgg){
            TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalogNameAgg").field("catalogName");
            if(null != catalogNameAgg){
                catalogIdAgg.subAggregation(catalogNameAgg);
            }
        }

        // 设置属性聚合
        NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg", "attrs");
        if(null != attrAgg){
            TermsAggregationBuilder attrsIdAgg = AggregationBuilders.terms("attrIdAgg").field("attrs.attrId");
            if(null != attrsIdAgg){
                attrAgg.subAggregation(attrsIdAgg);
                TermsAggregationBuilder attrsNameAgg = AggregationBuilders.terms("attrNameAgg").field("attrs.attrName");
                if(null != attrsNameAgg){
                    attrsIdAgg.subAggregation(attrsNameAgg);
                    TermsAggregationBuilder attrsValueAgg = AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue");
                    if(null != attrsValueAgg){
                        attrsIdAgg.subAggregation(attrsValueAgg);
                    }
                }
            }
        }

        // 将聚合添加到请求条件中
        sourceBuilder.aggregation(brandIdAgg);
        sourceBuilder.aggregation(catalogIdAgg);
        sourceBuilder.aggregation(attrAgg);


        // 创建搜索请求对象并设置索引和搜索源
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("product");
        searchRequest.source(sourceBuilder);

        return searchRequest;
    }
}
